/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package se.bth.ke.firstfriend.depend;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * @author nico.rehwaldt
 */
public class AprioriExecutable {
        
    private final String executable;

    private String inFile;
    private String outFile;

    private ArrayList<String> arguments = new ArrayList();

    private BufferedWriter writer;
    
    private Logger logger;
    private Level level;
    
    public AprioriExecutable(String executable) {
        this.executable = executable;
    }

    public AprioriExecutable read(File inFile) {
        return read(inFile.getAbsolutePath());
    }
    
    public AprioriExecutable read(String inFile) {
        this.inFile = inFile;
        return this;
    }

    public AprioriExecutable write(File outFile) {
        return write(outFile.getAbsolutePath());
    }
    
    public AprioriExecutable write(String outFile) {
        this.outFile = outFile;
        return this;
    }

    public AprioriExecutable logTo(Logger logger, Level level) {
        if (writer != null) {
            throw new IllegalStateException("Can not log both to a writer and to a logger");
        }
        
        if (logger == null || level == null) {
            throw new IllegalArgumentException("Arguments may not be null");
        }
        
        this.logger = logger;
        this.level = level;
        
        return this;
    }
    
    public AprioriExecutable logTo(Writer writer) {
        if (logger != null) {
            throw new IllegalStateException("Can not log both to a writer and to a logger");
        }
        
        if (writer instanceof BufferedWriter) {
            this.writer = (BufferedWriter) writer;
        } else {
            this.writer = new BufferedWriter(writer);
        }
        return this;
    }
    
    public int executeWithArgs(String ... args) throws IOException {
        arguments = new ArrayList<String>(Arrays.asList(args));
        return execute();
    }
    
    public int executeWithArgs(Map<String, String> args) throws IOException {
        arguments = new ArrayList<String>();
        for (Map.Entry<String, String> entry: args.entrySet()) {
            arguments.add(entry.getKey() + entry.getValue());
        }
        
        return execute();
    }
    
    public int execute() throws IOException {
        if (arguments == null) {
            arguments = new ArrayList<String>();
        }
        
        if (inFile == null) {
            throw new IllegalStateException("No inFile specified");
        }
        
        if (outFile == null) {
            throw new IllegalArgumentException("no outFile specified");
        }
        
        arguments.add(0, executable);
        arguments.add(inFile);
        arguments.add(outFile);
        
        ProcessBuilder builder = new ProcessBuilder(arguments);        
        builder.redirectErrorStream(true);

        Process p = builder.start();

        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while (true) {
            String line = reader.readLine();
            if (line == null) break;

            if (logger != null) {
                logger.log(level, line);
            } else if (writer != null) {
                writer.write(line);
            }
        }

        reader.close();

        return p.exitValue();        
    }
}
